/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-08-06 08:06:56
 * @LastEditTime: 2021-09-06 14:55:36
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#include "f_pcie.h"
#include "parameters.h"
#include "f_pcie_common.h"
//#include "interrupt.h"
#include "ft_io.h"
//#include "gicv3.h"
#include <string.h>
#include "ft_debug.h"
#define FPCIE_TEST_DEBUG_TAG "FPCIE_TEST"
#define FPCIE_TEST_ERROR(format, ...) FT_DEBUG_PRINT_E(FPCIE_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_TEST_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FPCIE_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_TEST_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FPCIE_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_TEST_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FPCIE_TEST_DEBUG_TAG, format, ##__VA_ARGS__)

#define DMA_TEST_DESC_NUM DMA_MAX_DESC_NUM
#define DMA_TEST_DESC_BUF_SIZE PCIE_BUF_SIZE
#define DMA_TEST_TOTAL_BUFSIZE (DMA_TEST_DESC_NUM * DMA_TEST_DESC_BUF_SIZE)
#define DMA_MAX_DESC_NUM 64
#define PCIE_BUF_SIZE (1024 * 1024)

#define TEST_DMA_LENGTH (0x1000000)

#define BAR_SIZE 0x100000
#define BAR0_MEM 0x80000000
#define BAR1_MEM (BAR0_MEM + BAR_SIZE)
#define BAR2_MEM (BAR1_MEM + BAR_SIZE)
#define BAR3_MEM (BAR2_MEM + BAR_SIZE)
#define BAR4_MEM (BAR3_MEM + BAR_SIZE)
#define BAR5_MEM (BAR4_MEM + BAR_SIZE)

FpcieId pcie_id = {
    .vendor = 0x0731,
    .device = 0x7200,
};

FPcie pcie_obj;
uint8_t *write_dma_buf = (uint8_t *)0xa0000000;
uint8_t *read_dma_buf = (uint8_t *)0xd0000000;

volatile int dma_irq_read_done = 0;
volatile int dma_irq_write_done = 0;

struct FPcieDmaDescriptor write_desc[DMA_MAX_DESC_NUM];
struct FPcieDmaDescriptor read_desc[DMA_MAX_DESC_NUM];
struct FPcieDmaDescriptor *desc;

static void FPcieHwInit(void)
{
    FPcieCfgInitialize(&pcie_obj, FPcieLookupConfig(FT_PCIE0_ID));
}

#ifndef CONFIG_PCIE_DEMO_POLL

static void IrqTestInit(void)
{
    /* interrupt init */
}

static void FPcieIrqTxTest(void *args)
{
    (void)args;
    dma_irq_write_done = 1;
}

static void FPcieIrqRxTest(void *args)
{
    (void)args;
    dma_irq_read_done = 1;
}

#endif

void FPCieTest(void)
{
    int i;
    u64 dev_bar_addr;
    u64 data;
    FPcieHwInit();

#ifndef CONFIG_PCIE_DEMO_POLL
    IrqTestInit();
    FPcieMiscIrqSet(&pcie_obj, FPCIE_PEU0_C0);
    FPcieSetHandler(&pcie_obj, FPCIE_HANDLER_DMASEND, FPcieIrqTxTest, NULL);
    FPcieSetHandler(&pcie_obj, FPCIE_HANDLER_DMARECV, FPcieIrqRxTest, NULL);
    InterruptSetPriority(pcie_obj.config.irq_num, 0);
    InterruptInstall(pcie_obj.config.irq_num, (IrqHandler)FPcieMiscIrq, &pcie_obj, "pcie1");
    InterruptUmask(pcie_obj.config.irq_num);
#endif

    FPcieFetchDeviceInBus(&pcie_obj, 0);

    dev_bar_addr = FPcieFindBusDeviceBarAddress(&pcie_obj, &pcie_id, 1, 0);
    FPCIE_TEST_DEBUG_I("dev_bar_addr is %llx ", dev_bar_addr);

    /* 读写bar测试 */
    data = FtIn64(dev_bar_addr);
    FPCIE_TEST_DEBUG_I("r>>dat : [0x%llx]", data);

    data = 0xab48ab48;
    FPCIE_TEST_DEBUG_I("w>>dat : [0x%llx]", data);
    FtOut64(dev_bar_addr, data);

    data = FtIn64(dev_bar_addr);
    FPCIE_TEST_DEBUG_I("r>>dat : [0x%llx]", data);

    /* Dma transfer test  */

    for (i = 0; i < DMA_TEST_TOTAL_BUFSIZE; i++)
    {
        write_dma_buf[i] = i;
    }

    desc = write_desc;

    for (i = 0; i < DMA_TEST_DESC_NUM - 1; i++)
    {
        FPcieDmaDescSet((uintptr)write_dma_buf + (i * DMA_TEST_DESC_BUF_SIZE), (uintptr)dev_bar_addr + (i * DMA_TEST_DESC_BUF_SIZE), TEST_DMA_LENGTH, desc + i, desc + i + 1);
    }

    FPcieDmaDescSet((uintptr)write_dma_buf + (i * DMA_TEST_DESC_BUF_SIZE), (uintptr)dev_bar_addr + (i * DMA_TEST_DESC_BUF_SIZE), TEST_DMA_LENGTH, desc + i, NULL);
    FPcieDmaWrite(pcie_obj.config.control_c0_address, desc);

#ifndef CONFIG_PCIE_DEMO_POLL
    while (1)
    {
        if (dma_irq_write_done == 1)
        {
            FPCIE_TEST_DEBUG_I("  dma_irq_write_done  ");
            dma_irq_write_done = 0;
            break;
        }
    }
#else
    FPcieDmaPollDone(desc + i, 0xffffffff);
#endif

    for (i = 0; i < DMA_TEST_TOTAL_BUFSIZE; i++)
    {
        read_dma_buf[i] = 0;
    }

    desc = read_desc;

    for (i = 0; i < DMA_TEST_DESC_NUM - 1; i++)
    {
        FPcieDmaDescSet((uintptr)read_dma_buf + (i * DMA_TEST_DESC_BUF_SIZE), (uintptr)dev_bar_addr + (i * DMA_TEST_DESC_BUF_SIZE), TEST_DMA_LENGTH, desc + i, desc + i + 1);
    }

    FPcieDmaDescSet((uintptr)read_dma_buf + (i * DMA_TEST_DESC_BUF_SIZE), (uintptr)dev_bar_addr + (i * DMA_TEST_DESC_BUF_SIZE), TEST_DMA_LENGTH, desc + i, NULL);
    FPcieDmaRead(pcie_obj.config.control_c0_address, desc);

#ifndef CONFIG_PCIE_DEMO_POLL
    while (1)
    {
        if (dma_irq_read_done == 1)
        {
            dma_irq_read_done = 0;
            FPCIE_TEST_DEBUG_I("  dma_irq_read_done  ");
            break;
        }
    }
#else
    FPcieDmaPollDone(desc + i, 0xffffffff);
#endif

    if (0 == memcmp(read_dma_buf, write_dma_buf, DMA_TEST_TOTAL_BUFSIZE))
    {
        FPCIE_TEST_DEBUG_I("PCIE DMA TRANSFER SUCCESSFUL! ");
    }
    else
    {
        FPCIE_TEST_DEBUG_E("PCIE DMA TRANSFER FAILED! ");
    }
}
